#pragma once
#include "Business/Business.h"
#include "Business/DealingHistory.h"
#include "Business/CustomerPosition.h"
#include "Business/Leg.h"
#include "StatusMachine/StatusMachine.h"
#include "Business/Dealing.h"

class Customer;
class MarketStorage;
class QueueContext;
class DealingRepository;
class CancellationRepository;

class OpenSignalBusiness;

namespace OpenSignalBusinessStatusMachine {
	class Event
	{
	public:
		enum TYPE {NONE,MARKET_EVENT, DEALING_EVENT,START_COMMAND, EDIT_COMMAND,CLEAR_COMMAND,OPEN_SIGNAL_COMMAND};
		explicit Event(TYPE type = NONE);
		explicit Event(Market const& market);
		explicit Event(Dealing const& dealing);
		int GetType() const { return m_type; }
		Market const& GetMarket() const { return *(Market*)m_data; }
		Dealing const& GetDealing() const { return *(Dealing*)m_data; }

	private:
		int m_type;
		char m_data[1024];
	};

	typedef Status<OpenSignalBusiness,Event> StatusT;
	class StatusBase : public StatusT
	{
	public:
		StatusBase(std::string const& name, OpenSignalBusiness& context):StatusT(name,context){}
	private:
		virtual void DoBefore();
	};
	typedef ConditionBase<OpenSignalBusiness,Event> ConditionT;
	typedef StatusMachine<OpenSignalBusiness,Event> StatusMachineT;


#define DEFINE_CONDITION(condition_name)						\
	class condition_name : public ConditionT					\
	{															\
	public:														\
	explicit condition_name(OpenSignalBusiness& context)	\
	:ConditionT(context){}										\
	virtual ~condition_name() {}								\
	private:													\
	virtual bool DoCheck(Event const& event);					\
	}

	DEFINE_CONDITION(OpenSignalCondition);
// 	DEFINE_CONDITION(OrderedCondition);
// 	DEFINE_CONDITION(AllCanceledCondition);
	DEFINE_CONDITION(PartialDealCondition);
	DEFINE_CONDITION(CompleteDealCondition);
	DEFINE_CONDITION(DealedCondition);
	DEFINE_CONDITION(ClearCondition);
	DEFINE_CONDITION(OffsetMarketCondition);
	DEFINE_CONDITION(StopMarketCondition);
	DEFINE_CONDITION(AllOffsetedCondition);
	DEFINE_CONDITION(EditCondition);
	DEFINE_CONDITION(StartCondition);
#undef DEFINE_CONDITION

#define DEFINE_STATUS(class_name,name)					\
	class class_name : public StatusBase					\
	{														\
	public:													\
	explicit class_name(OpenSignalBusiness& context)		\
	:StatusBase(name,context){}							\
	virtual ~class_name(){}								\
	private:											\
	virtual void DoExecute(Event const& event);			\
	}

	DEFINE_STATUS(EditableStatus,"editable");
	DEFINE_STATUS(StartStatus,"start");
	DEFINE_STATUS(OpenSentStatus,"open sent");
	DEFINE_STATUS(CancelSentStatus,"cancel sent");
	DEFINE_STATUS(OpenedStatus,"opened");
	DEFINE_STATUS(OffsetSentStatus,"offset sent");
	DEFINE_STATUS(StopSentStatus,"stop sent");
	DEFINE_STATUS(ClearSentStatus,"clear sent");
}


class OpenSignalArgument
{
public:
	OpenSignalArgument(int contract,int maxQuantity,double open,double offset,double stop)
		:m_contract(contract),m_maxQuantity(maxQuantity),m_open(open),m_offset(offset),m_stop(stop)
	{
	}
	int GetContract() const {return m_contract;}
	int GetMaxQuantity() const {return m_maxQuantity;}
	double GetOpen() const {return m_open;}
	double GetOffset() const {return m_offset;}
	double GetStop() const {return m_stop;}

	void UpdatePrice(OpenSignalArgument const& other)
	{
		m_open = other.GetOpen();
		m_offset = other.GetOffset();
		m_stop = other.GetStop();
	}
private:
	int m_contract;
	int m_maxQuantity;
	double m_open;
	double m_offset;
	double m_stop;
};

class OpenSignalBusinessSnapshot 
{
public:
	OpenSignalBusinessSnapshot(char const* status,DirectionFlag::FLAG direction,int quantity,double price)
		:m_status(status),m_direction(direction),m_quantity(quantity),m_price(price)
	{
	}
	char const* GetStatus() const {return m_status;}
	DirectionFlag::FLAG GetDirection() const {return m_direction;}
	int GetQuantity() const {return m_quantity;}
	double GetPrice() const {return m_price;}

	bool operator==(OpenSignalBusinessSnapshot const& other) const
	{
		return m_status == other.m_status && m_direction == other.m_direction &&
			m_quantity == other.m_quantity && m_price == other.m_price;
	}
	bool operator!=(OpenSignalBusinessSnapshot const& other) const
	{
		return !operator==(other);
	}
private:
	char const * m_status;
	DirectionFlag::FLAG m_direction;
	int m_quantity;
	double m_price;
};

class OpenSignalBusiness : public Business
{
	class Legs
	{
	public:
		Legs(Market const& market,OpenSignalArgument const& argument)
			:m_openLeg(market,GetOpenDirection(argument),OperationFlag::OPEN),
			m_offsetLeg(market,m_openLeg.GetNegativeDirection(),OperationFlag::OFFSET_TODAY)
		{
		}
		Leg const& GetOpenLeg() const { return m_openLeg; }
		Leg const& GetOffsetLeg() const { return m_offsetLeg; }
	private:
		Leg m_openLeg;
		Leg m_offsetLeg;

		static DirectionFlag::FLAG GetOpenDirection(OpenSignalArgument const& argument)
		{
			return argument.GetOpen() < argument.GetOffset() ? DirectionFlag::BUY : DirectionFlag::SELL;
		}
	};
public:

	OpenSignalBusiness(Customer& customer,
		OpenSignalArgument const& argument,
		MarketStorage const& marketStorage,
		QueueContext& queueContext, 
		DealingRepository& dealingRepository,
		CancellationRepository& cancellationRepository);

	virtual ~OpenSignalBusiness();

	OpenSignalArgument const& GetArgument() const { return m_argument; }
	bool IsEditable() const;

	OpenSignalBusinessSnapshot GetSnapshot();
	void UpdateUI(OpenSignalBusinessSnapshot const& snapshot);

	void Init();
	void Open();
	void Cancel();
	void Offset();
	void Stop();
	void Clear();
	void CheckMarket();

	int GetOpenQuantity() const;
	int GetContract() const {return m_argument.GetContract();}
	char const* GetCode() const;
	int GetQuantity() const;
	double GetPrice() const;

	bool CanOffset() const;
	bool CanStop() const;
private:
	Order CreateOpenOrder(int quantity) const;
	Order CreateOffsetOrder(double offsetPrice) const;

	virtual void DoOnInit();
	virtual void DoOnMarket(Market const& market);
	virtual void DoOnPendingMarket(PendingMarket const& pendingMarket);
	virtual void DoOnDealing(Dealing const& dealing);

	virtual void DoOnTimeout(RequestTimeout const& requestTimeout);
	virtual void DoOnTrade(Trade const& trade);
	virtual void DoOnCommand(Command const& command);
	virtual void DoOnExchangeStatus(int exchangeStatus);

	void UpdateArgument(OpenSignalArgument const& argument);

	OpenSignalArgument m_argument;
	MarketStorage const& m_marketStorage;
	QueueContext& m_queueContext;
	DealingRepository& m_dealingRepository;
	CancellationRepository& m_cancellationRepository;
	OpenSignalBusinessStatusMachine::StatusMachineT* m_machine;
	std::auto_ptr<Legs> m_legs;

	PositionValue m_position;

	Dealing* m_openDealing;
	
};
